package org.linlinjava.litemall.wx.web;

import cn.hutool.core.collection.CollUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.linlinjava.litemall.core.system.SystemConfig;
import org.linlinjava.litemall.core.util.JacksonUtil;
import org.linlinjava.litemall.core.util.ResponseUtil;
import org.linlinjava.litemall.db.domain.*;
import org.linlinjava.litemall.db.service.*;
import org.linlinjava.litemall.db.util.DateUtil;
import org.linlinjava.litemall.wx.annotation.LoginUser;
import org.linlinjava.litemall.wx.util.CloneUtil;
import org.linlinjava.litemall.wx.vo.CartVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collector;
import java.util.stream.Collectors;

import static org.linlinjava.litemall.wx.util.WxResponseCode.GOODS_NO_STOCK;
import static org.linlinjava.litemall.wx.util.WxResponseCode.GOODS_UNSHELVE;

/**
 * 用户购物车服务
 */
@RestController
@RequestMapping("/wx/cart")
@Validated
@Api("用户购物车服务")
public class WxCartController {
    private final Log logger = LogFactory.getLog(WxCartController.class);

    @Autowired
    private CartService cartService;
    @Autowired
    private GoodsService goodsService;
    @Autowired
    private AddressService addressService;
    @Autowired
    private CategoryService categoryService;
    @Autowired
    private CouponUserService couponUserService;
    @Autowired
    private CouponVerifyService couponVerifyService;

    /**
     * 用户购物车信息
     *
     * @param userId 用户ID
     * @return 用户购物车信息
     */
    @GetMapping("index")
    @ApiOperation("用户购物车信息")
    public Object index(@LoginUser Integer userId) {
        if (userId == null) {
            return ResponseUtil.unlogin();
        }

        List<LitemallCart> list = cartService.queryByUid(userId);
        List<LitemallCart> cartList = new ArrayList<>();
        // TODO
        // 如果系统检查商品已删除或已下架，则系统自动删除。
        // 更好的效果应该是告知用户商品失效，允许用户点击按钮来清除失效商品。
        for (LitemallCart cart : list) {
            LitemallGoods goods = goodsService.findById(cart.getGoodsId());
            if (goods == null || !goods.getIsOnSale()) {
                cartService.deleteById(cart.getId());
                logger.debug("系统自动删除失效购物车商品 goodsId=" + cart.getGoodsId());
            }
            else{
                cartList.add(cart);
            }
        }

        List<CartVo> cartVos = CloneUtil.cloneList(cartList, CartVo.class);

        cartVos.forEach(cartVo -> {
            LitemallGoods good = goodsService.findById(cartVo.getGoodsId());
            cartVo.setCategory(categoryService.findById(good.getCategoryId()).getName());
            cartVo.setDesc(good.getBrief());
            cartVo.setPicUrl(good.getPicUrl());
            // 秒杀信息
            LitemallGoods killGood = goodsService.findByGoodIdBetween(cartVo.getGoodsId(), DateUtil.currentTime());
            if (killGood != null) {
                cartVo.setIsKill(true);
                cartVo.setKillPrice(killGood.getKillPrice());
            }
        });

        Map<String, List<CartVo>> cartLists = cartVos.stream().collect(Collectors.groupingBy(CartVo::getCategory));

        Integer goodsCount = 0;
        BigDecimal goodsAmount = new BigDecimal("0.00");
        Integer checkedGoodsCount = 0;
        BigDecimal checkedGoodsAmount = new BigDecimal("0.00");
        for (LitemallCart cart : cartList) {
            goodsCount += cart.getNumber();
            goodsAmount = goodsAmount.add(cart.getPrice().multiply(new BigDecimal(cart.getNumber())));
            if (cart.getChecked()) {
                checkedGoodsCount += cart.getNumber();
                checkedGoodsAmount = checkedGoodsAmount.add(cart.getPrice().multiply(new BigDecimal(cart.getNumber())));
            }
        }
        Map<String, Object> cartTotal = new HashMap<>();
        cartTotal.put("goodsCount", goodsCount);
        cartTotal.put("goodsAmount", goodsAmount);
        cartTotal.put("checkedGoodsCount", checkedGoodsCount);
        cartTotal.put("checkedGoodsAmount", checkedGoodsAmount);

        Map<String, Object> result = new HashMap<>();
        result.put("cartList", cartLists);
        result.put("cartTotal", cartTotal);

        return ResponseUtil.ok(result);
    }

    /**
     * 加入商品到购物车
     * <p>
     * 如果已经存在购物车货品，则增加数量；
     * 否则添加新的购物车货品项。
     *
     * @param userId 用户ID
     * @param cart   购物车商品信息， { goodsId: xxx, productId: xxx, number: xxx }
     * @return 加入购物车操作结果
     */
    @PostMapping("add")
    @ApiOperation("加入商品到购物车")
    public Object add(@LoginUser Integer userId, @RequestBody LitemallCart cart) {
        if (userId == null) {
            return ResponseUtil.unlogin();
        }
        if (cart == null) {
            return ResponseUtil.badArgument();
        }

        Integer number = cart.getNumber().intValue();
        Integer goodsId = cart.getGoodsId();
        if(number <= 0){
            return ResponseUtil.badArgument();
        }

        if (!ObjectUtils.allNotNull(number, goodsId)) {
            return ResponseUtil.badArgument();
        }

        //判断商品是否可以购买
        LitemallGoods goods = goodsService.findById(goodsId);
        if (goods == null || !goods.getIsOnSale()) {
            return ResponseUtil.fail(GOODS_UNSHELVE, "商品已下架");
        }

        //判断购物车中是否存在此规格商品
        LitemallCart existCart = cartService.queryExist(goodsId, userId);
        LitemallGoods killBetween = goodsService.findByGoodIdBetween(goodsId, DateUtil.currentTime());
        LitemallGoods killLeGe = goodsService.findByGoodGe(goodsId);
        if (existCart == null) {
            // 判断是否库存足
            if (!iSStock(killBetween, killLeGe, goods, number)) {
                return ResponseUtil.fail(GOODS_NO_STOCK, "库存不足");
            }

            cart.setId(null);
            cart.setGoodsName((goods.getName()));
            if(StringUtils.isEmpty(goods.getPicUrl())){
                cart.setPicUrl(goods.getPicUrl());
            }
            else{
                cart.setPicUrl(goods.getPicUrl());
            }
            cart.setPrice(goods.getRetailPrice());
            cart.setUserId(userId);
            cart.setChecked(true);
            cartService.add(cart);
        } else {
            // 取得规格的信息,判断规格库存
            int num = existCart.getNumber() + number;
            if (!iSStock(killBetween, killLeGe, goods, num)) {
                return ResponseUtil.fail(GOODS_NO_STOCK, "库存不足");
            }
            existCart.setNumber((short) num);
            if (cartService.updateById(existCart) == 0) {
                return ResponseUtil.updatedDataFailed();
            }
        }

        return goodscount(userId);
    }

    private Boolean iSStock(LitemallGoods killBetween, LitemallGoods killLeGe, LitemallGoods goods ,Integer number) {
        // 不在秒杀时间段
        if (killBetween == null) {
            // 有秒杀商品，并且大于当前时间
            if (killLeGe != null) {
                // 商品剩余数量 小于大于 秒杀商品数量   就是必须保证秒杀商品数量够
                if (goods.getNumber() <= killLeGe.getNumber()) {
                    return false;
                }
            }
            // 无秒杀商品
            else {
                if (number > goods.getNumber()) {
                    return false;
                }
            }
        }
        // 当前时间有秒杀商品， 增加的数量不能大于 秒杀商品数量
        else if (number > (killBetween.getKillNumber() - killBetween.getInitialNumber())){
            return false;
        }
        return true;
    }

    /**
     * 立即购买
     * <p>
     * 和add方法的区别在于：
     * 1. 如果购物车内已经存在购物车货品，前者的逻辑是数量添加，这里的逻辑是数量覆盖
     * 2. 添加成功以后，前者的逻辑是返回当前购物车商品数量，这里的逻辑是返回对应购物车项的ID
     *
     * @param userId 用户ID
     * @param cart   购物车商品信息， { goodsId: xxx, productId: xxx, number: xxx }
     * @return 立即购买操作结果
     */
    @PostMapping("fastadd")
    @ApiOperation("立即购买")
    public Object fastadd(@LoginUser Integer userId, @RequestBody LitemallCart cart) {
//        if (userId == null) {
//            return ResponseUtil.unlogin();
//        }
//        if (cart == null) {
//            return ResponseUtil.badArgument();
//        }
//
//        Integer number = cart.getNumber().intValue();
//        Integer goodsId = cart.getGoodsId();
//        if (!ObjectUtils.allNotNull(number, goodsId)) {
//            return ResponseUtil.badArgument();
//        }
//        if(number <= 0){
//            return ResponseUtil.badArgument();
//        }
//
//        //判断商品是否可以购买
//        LitemallGoods goods = goodsService.findById(goodsId);
//        if (goods == null || !goods.getIsOnSale()) {
//            return ResponseUtil.fail(GOODS_UNSHELVE, "商品已下架");
//        }
//
//        LitemallGoodsProduct product = productService.queryByGid(goodsId).get(0);
//        //判断购物车中是否存在此规格商品
//        LitemallCart existCart = cartService.queryExist(goodsId, userId);
//        if (existCart == null) {
//            //取得规格的信息,判断规格库存
//            if (product == null || number > product.getNumber()) {
//                return ResponseUtil.fail(GOODS_NO_STOCK, "库存不足");
//            }
//
//            cart.setId(null);
//            cart.setGoodsSn(goods.getGoodsSn());
//            cart.setGoodsName((goods.getName()));
//            if(StringUtils.isEmpty(product.getUrl())){
//                cart.setPicUrl(goods.getPicUrl());
//            }
//            else{
//                cart.setPicUrl(product.getUrl());
//            }
//            cart.setPrice(goods.getRetailPrice());
//            cart.setSpecifications(product.getSpecifications());
//            cart.setUserId(userId);
//            cart.setChecked(true);
//            cartService.add(cart);
//        } else {
//            //取得规格的信息,判断规格库存
//            int num = number;
//            if (num > product.getNumber()) {
//                return ResponseUtil.fail(GOODS_NO_STOCK, "库存不足");
//            }
//            existCart.setNumber((short) num);
//            if (cartService.updateById(existCart) == 0) {
//                return ResponseUtil.updatedDataFailed();
//            }
//        }
//
//        return ResponseUtil.ok(existCart != null ? existCart.getId() : cart.getId());
        return null;
    }

    /**
     * 修改购物车商品货品数量
     *
     * @param userId 用户ID
     * @param cart   购物车商品信息， { id: xxx, goodsId: xxx, productId: xxx, number: xxx }
     * @return 修改结果
     */
    @PostMapping("update")
    @ApiOperation("修改购物车商品货品数量")
    public Object update(@LoginUser Integer userId, @RequestBody LitemallCart cart) {
        if (userId == null) {
            return ResponseUtil.unlogin();
        }
        Integer number = cart.getNumber().intValue();
        Integer goodsId = cart.getGoodsId();
        if (!ObjectUtils.allNotNull(number, goodsId)) {
            return ResponseUtil.badArgument();
        }
        if(number <= 0){
            return ResponseUtil.badArgument();
        }

        //判断是否存在该订单
        // 如果不存在，直接返回错误
        LitemallCart existCart = cartService.findById(userId, goodsId);
        if (existCart == null) {
            return ResponseUtil.badArgumentValue();
        }

        //判断商品是否可以购买
        LitemallGoods goods = goodsService.findById(goodsId);
        if (goods == null || !goods.getIsOnSale()) {
            return ResponseUtil.fail(GOODS_UNSHELVE, "商品已下架");
        }

        //取得规格的信息,判断规格库存
        if (goods.getNumber() < number) {
            return ResponseUtil.fail(GOODS_UNSHELVE, "库存不足");
        }

        existCart.setNumber(number.shortValue());
        if (cartService.updateById(existCart) == 0) {
            return ResponseUtil.updatedDataFailed();
        }
        return ResponseUtil.ok();
    }

    /**
     * 购物车商品货品勾选状态
     * <p>
     * 如果原来没有勾选，则设置勾选状态；如果商品已经勾选，则设置非勾选状态。
     *
     * @param userId 用户ID
     * @param body   购物车商品信息， { productIds: xxx, isChecked: 1/0 }
     * @return 购物车信息
     */
    @PostMapping("checked")
    @ApiOperation("购物车商品货品勾选状态")
    public Object checked(@LoginUser Integer userId, @RequestBody String body) {
        if (userId == null) {
            return ResponseUtil.unlogin();
        }
        if (body == null) {
            return ResponseUtil.badArgument();
        }

        List<Integer> productIds = JacksonUtil.parseIntegerList(body, "productIds");
        if (productIds == null) {
            return ResponseUtil.badArgument();
        }

        Integer checkValue = JacksonUtil.parseInteger(body, "isChecked");
        if (checkValue == null) {
            return ResponseUtil.badArgument();
        }
        Boolean isChecked = (checkValue == 1);

        cartService.updateCheck(userId, productIds, isChecked);
        return index(userId);
    }

    /**
     * 购物车商品删除
     *
     * @param userId 用户ID
     * @param goodsId   商品Id
     * @return 购物车信息
     * 成功则
     * {
     * errno: 0,
     * errmsg: '成功',
     * data: xxx
     * }
     * 失败则 { errno: XXX, errmsg: XXX }
     */
    @PostMapping("delete")
    @ApiOperation("购物车商品删除")
    public Object delete(@LoginUser Integer userId, @RequestBody List<Integer> goodsId) {
        if (userId == null) {
            return ResponseUtil.unlogin();
        }
        if (CollUtil.isEmpty(goodsId)) {
            return ResponseUtil.badArgument();
        }

        goodsId.forEach(good ->{
            cartService.delete(good, userId);
        });
        return index(userId);
    }

    /**
     * 购物车商品货品数量
     * <p>
     * 如果用户没有登录，则返回空数据。
     *
     * @param userId 用户ID
     * @return 购物车商品货品数量
     */
    @GetMapping("goodscount")
    @ApiOperation("购物车商品货品数量")
    public Object goodscount(@LoginUser Integer userId) {
        if (userId == null) {
            return ResponseUtil.ok(0);
        }

        int goodsCount = 0;
        List<LitemallCart> cartList = cartService.queryByUid(userId);
        for (LitemallCart cart : cartList) {
            goodsCount += cart.getNumber();
        }

        return ResponseUtil.ok(goodsCount);
    }

    /**
     * 购物车下单
     *
     * @param userId    用户ID
     * @param cartId    购物车商品ID：
     *                  如果购物车商品ID是空，则下单当前用户所有购物车商品；
     *                  如果购物车商品ID非空，则只下单当前购物车商品。
     * @param addressId 收货地址ID：
     *                  如果收货地址ID是空，则查询当前用户的默认地址。
     * @return 购物车操作结果
     */
    @GetMapping("checkout")
    @ApiOperation("购物车下单")
    public Object checkout(@LoginUser Integer userId, Integer cartId, Integer addressId) {
        if (userId == null) {
            return ResponseUtil.unlogin();
        }
        // 收货地址
        LitemallAddress checkedAddress = null;
        if (addressId == null || addressId.equals(0)) {
            checkedAddress = addressService.findDefault(userId);
            // 如果仍然没有地址，则是没有收货地址
            // 返回一个空的地址id=0，这样前端则会提醒添加地址
            if (checkedAddress == null) {
                checkedAddress = new LitemallAddress();
                checkedAddress.setId(0);
                addressId = 0;
            } else {
                addressId = checkedAddress.getId();
            }

        } else {
            checkedAddress = addressService.query(userId, addressId);
            // 如果null, 则报错
            if (checkedAddress == null) {
                return ResponseUtil.badArgumentValue();
            }
        }


        // 商品价格
        List<LitemallCart> checkedGoodsList;
        if (cartId == null || cartId.equals(0)) {
            checkedGoodsList = cartService.queryByUidAndChecked(userId);
        } else {
            LitemallCart cart = cartService.findById(userId, cartId);
            if (cart == null) {
                return ResponseUtil.badArgumentValue();
            }
            checkedGoodsList = new ArrayList<>(1);
            checkedGoodsList.add(cart);
        }
        BigDecimal checkedGoodsPrice = new BigDecimal(0.00);
        for (LitemallCart cart : checkedGoodsList) {
            checkedGoodsPrice = checkedGoodsPrice.add(cart.getPrice().multiply(new BigDecimal(cart.getNumber())));
        }

        // 计算优惠券可用情况
        BigDecimal tmpCouponPrice = new BigDecimal(0.00);
        List<LitemallCouponUser> couponUserList = couponUserService.queryAll(userId);
        for(LitemallCouponUser couponUser : couponUserList){
            LitemallCoupon coupon = couponVerifyService.checkCoupon(userId, couponUser.getCouponId(), couponUser.getId(), checkedGoodsPrice, checkedGoodsList);
            if(coupon == null){
                continue;
            }
        }

        // 根据订单商品总价计算运费，满88则免运费，否则8元；
        BigDecimal freightPrice = new BigDecimal(0.00);
        if (checkedGoodsPrice.compareTo(SystemConfig.getFreightLimit()) < 0) {
            freightPrice = SystemConfig.getFreight();
        }

        // 可以使用的其他钱，例如用户积分
        BigDecimal integralPrice = new BigDecimal(0.00);

        // 订单费用
        BigDecimal orderTotalPrice = checkedGoodsPrice.add(freightPrice).max(new BigDecimal(0.00));

        BigDecimal actualPrice = orderTotalPrice.subtract(integralPrice);

        Map<String, Object> data = new HashMap<>();
        data.put("addressId", addressId);
        data.put("cartId", cartId);
        data.put("checkedAddress", checkedAddress);
        data.put("goodsTotalPrice", checkedGoodsPrice);
        data.put("freightPrice", freightPrice);
        data.put("orderTotalPrice", orderTotalPrice);
        data.put("actualPrice", actualPrice);
        data.put("checkedGoodsList", checkedGoodsList);
        return ResponseUtil.ok(data);
    }
}
